# 装饰器 timethis就是一个装饰器，返回一个函数
# import time
# from functools import wraps
#
#
# def timethis(func):
#     '''
#     Decorator that reports the execution time.
#     '''
#
#     @wraps(func)
#     def wrapper(*args, **kwargs):
#         start = time.time()
#         result = func(*args, **kwargs)
#         end = time.time()
#         print(func.__name__, end - start)
#         return result
#
#     return wrapper
#
# 装饰器 timethis等同于 countdown = timethis(countdown)
# @timethis
# def countdown(n):
#     '''
#     Counts down
#     '''
#     while n > 0:
#         n -= 1
# @staticmethod，为类方法设置静态属性 , @classmethod将方法定义为类方法，可接受cls参数
# @property 将方法定义为属性，访问时不需要括号
# 任何时候你定义装饰器的时候，都应该使用 functools 库中的 @wraps 装饰器来注解底层包装函数
# 如果不使用 @wraps ， 那么被装饰函数丢失了所有有用的信息。countdown的名字会变成wrapper， __doc__ 会变成 None
# @wraps 有一个重要特征是它能让你通过属性 __wrapped__ 直接访问被包装函数

# 当装饰器需要接受参数时
# from functools import wraps
# import logging
#
#
# def logged(level, name=None, message=None):
#     """
#     Add logging to a function. level is the logging
#     level, name is the logger name, and message is the
#     log message. If name and message aren't specified,
#     they default to the function's module and name.
#     """
#
#     def decorate(func):
#         logname = name if name else func.__module__
#         log = logging.getLogger(logname)
#         logmsg = message if message else func.__name__
#
#         @wraps(func)
#         def wrapper(*args, **kwargs):
#             log.log(level, logmsg)
#             return func(*args, **kwargs)
#
#         return wrapper
#
#     return decorate
#
#
# # Example use
# @logged(logging.DEBUG)
# def add(x, y):
#     return x + y
#
#
# @logged(logging.CRITICAL, 'example')
# def spam():
#     print('Spam!')

# 等价于：
# @decorator(x, y, z)
# def func(a, b):
#     pass

# def func(a, b):
#     pass
# func = decorator(x, y, z)(func)

# from functools import wraps, partial
# import logging
#
# def logged(func=None, *, level=logging.DEBUG, name=None, message=None):
#     if func is None:
#         return partial(logged, level=level, name=name, message=message)
#
#     logname = name if name else func.__module__
#     log = logging.getLogger(logname)
#     logmsg = message if message else func.__name__
#
#     @wraps(func)
#     def wrapper(*args, **kwargs):
#         log.log(level, logmsg)
#         return func(*args, **kwargs)
#
#     return wrapper
#
# # Example use
# @logged
# def add(x, y):
#     return x + y
#
# @logged(level=logging.CRITICAL, name='example')
# def spam():
#     print('Spam!') # 装饰器可以同时带参数或者不带参数
